﻿using System.Diagnostics.CodeAnalysis;
using DimensionsHelper.Common.Metadata.Script;

namespace DimensionsHelper.LanguageService.Syntax;

public class CategoryLiteral : Literal<Categorical>
{
    private SyntaxToken? _caretToken;
    private SyntaxToken? _dotDotToken;
    private IntegerLiteral? _integerValue;
    private Identifier? _rangeLeftIdentifier;
    private Identifier? _rangeRightIdentifier;

    internal CategoryLiteral(SyntaxNode? parent) : base(SyntaxKinds.Category, [], parent)
    {
        _integerValue = IntegerLiteral.Default;
    }


    /// <summary>
    ///     分类值区间带有的尖号(^)
    /// </summary>
    public SyntaxToken? CaretToken => _caretToken;


    /// <summary>
    ///     分类值区间可带有的".."
    /// </summary>
    public SyntaxToken? DotDotToken => _dotDotToken;


    /// <summary>
    ///     分类值区间的左值
    /// </summary>
    public Identifier? RangeLeft => _rangeLeftIdentifier;


    /// <summary>
    ///     分类值区间的右值
    /// </summary>
    public Identifier? RangeRight => _rangeRightIdentifier;


    /// <summary>
    ///     分类常量的整数值
    /// </summary>
    public IntegerLiteral? IntegerValue => _integerValue;


    /// <summary>
    ///     判断分类值是否是整数
    /// </summary>
    [MemberNotNullWhen(true, nameof(IntegerValue))]
    public bool IsIntegerValue => !IntegerLiteral.IsEmptyOrDefault(IntegerValue);

    /// <summary>
    ///     如果是单一的分类值，返回<see langword="true" />。此时，分类值属性是<see cref="RangeLeft" />
    /// </summary>
    public bool IsCategoryName =>
        !Identifier.IsDefaultOrEmpty(RangeLeft)
        && Identifier.IsDefaultOrEmpty(RangeRight);

    /// <summary>
    ///     如果是分类值区间，返回<see langword="true" />。
    /// </summary>
    [MemberNotNullWhen(true, nameof(DotDotToken))]
    public bool IsCategoryRange =>
        DotDotToken != null
        && DotDotToken.IsNode(SyntaxKinds.DotDotToken);


    public CategoryLiteral Update(SyntaxToken? caretToken, Identifier? leftBound, SyntaxToken? dotdotToken,
        Identifier? rightToken)
    {
        SetChildNullableField(ref _caretToken, SyntaxToken.IsNullOrEmpty, caretToken);
        SetChildNullableField(ref _dotDotToken, SyntaxToken.IsNullOrEmpty, dotdotToken);
        SetChildNullableField(ref _rangeLeftIdentifier, Identifier.IsDefaultOrEmpty, leftBound);
        SetChildNullableField(ref _rangeRightIdentifier, Identifier.IsDefaultOrEmpty, rightToken);
        return this;
    }


    public CategoryLiteral Update(IntegerLiteral value)
    {
        SetChildNullableField(ref _integerValue, IntegerLiteral.IsEmptyOrDefault, value);

        if (Value.Count > 0)
        {
            Value = new Categorical(value.Value);
        }

        return this;
    }
}


public static partial class NodeFactory
{
    public static CategoryLiteral CreateCategoryLiteral(SyntaxNode? parent, SyntaxToken? caretToken,
        Identifier? rangeLeft, SyntaxToken? dotDotToken, Identifier? rangeRight)
    {
        CategoryLiteral cat = new(parent);
        return cat.Update(caretToken, rangeLeft, dotDotToken, rangeRight);
    }


    public static CategoryLiteral CreateCategoryLiteral(SyntaxNode? parent, IntegerLiteral value)
    {
        CategoryLiteral cat = new(parent);
        return cat.Update(value);
    }
}